package com.xqboss.apps.service.user;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.constant.Config;
import com.xqboss.apps.domain.consumer.ConsumerRealName;
import com.xqboss.apps.domain.punch.PunchRule;
import com.xqboss.apps.domain.punch.PunchUserConfig;
import com.xqboss.apps.domain.user.UserIdentity;
import com.xqboss.apps.domain.user.UserIdentityRank;
import com.xqboss.apps.domain.user.UserIdentityRankSlot;
import com.xqboss.apps.enums.mq.AppMqDelayEnum;
import com.xqboss.apps.enums.user.UserIdentityPromotionEnum;
import com.xqboss.apps.enums.user.UserWalletEnum;
import com.xqboss.apps.enums.user.WalletChangeTypeEnum;
import com.xqboss.apps.mapper.user.UserIdentityRankMapper;
import com.xqboss.apps.service.consumer.ConsumerRealNameService;
import com.xqboss.apps.service.nft.NftService;
import com.xqboss.apps.service.punch.PunchRuleService;
import com.xqboss.apps.service.punch.PunchUserConfigService;
import com.xqboss.apps.vo.user.*;
import com.xqboss.common.constant.CacheConstants;
import com.xqboss.common.core.domain.R;
import com.xqboss.common.core.domain.entity.SysUser;
import com.xqboss.common.core.domain.model.LoginUser;
import com.xqboss.common.core.mq.MqSender;
import com.xqboss.common.core.redis.RedisCache;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.IdentityImgUtil;
import com.xqboss.common.utils.SecurityUtils;
import com.xqboss.common.utils.StringUtils;
import com.xqboss.system.domain.SysConfig;
import com.xqboss.system.mapper.SysUserMapper;
import com.xqboss.system.service.ISysConfigService;
import com.xqboss.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 用户身份-段位(UserIdentityRank)表服务实现类
 *
 * @author lujiahong
 * @since 2023-12-05 12:04:08
 */
@Slf4j
@Service
public class UserIdentityRankService extends ServiceImpl<UserIdentityRankMapper, UserIdentityRank> {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private NftService nftService;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysUserNftService sysUserNftService;

    @Autowired
    private UserIdentityRankMapper userIdentityRankMapper;

    @Autowired
    private UserIdentityService userIdentityService;

    @Autowired
    private UserRankUpgradeRecordService userRankUpgradeRecordService;

    @Autowired
    private SysUserWalletService sysUserWalletService;

    @Autowired
    private ConsumerRealNameService consumerRealNameService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private MqSender mqSender;

    @Autowired
    private PunchUserConfigService punchUserConfigService;

    @Autowired
    private PunchRuleService punchRuleService;

    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private UserIdentityRankSlotService userIdentityRankSlotService;


    /**
     * ***************************************TODO1: 判断当前用户表是否 实名 和 具备身份晋升功能呢
     * ***************************************{@link #identityPromotion}
     *
     * @param userId 用户id
     * @return IdentityPromotionVo （当前身份段位和是否可以晋升）
     */
    public IdentityPromotionVo identityPromotion(Long userId) {
        //0、首先判断当前用户有无实名，没有的话不进行下面的操作
        ConsumerRealName realName = consumerRealNameService.getUserRealNameOrNull(userId);
        if (realName==null) {
            return IdentityPromotionVo.builder().
                    isRealName(Boolean.FALSE).
                    build();
        }
        //1、当前段位信息
        UserIdentityRank userIdentityRank = getUserIdentityRank(userId);
        //当前段位
        String currentIdentity = userIdentityRank.getIdentityName()+(StringUtils.isBlank(userIdentityRank.getName())?"":userIdentityRank.getName());
        //2、是否显示身份晋升按钮
        Boolean haveNft = isHaveNft(userIdentityRank,userId);
        return IdentityPromotionVo.builder().
                isRealName(Boolean.TRUE).
                currentIdentityId(userIdentityRank.getId()).
                currentIdentity(currentIdentity).
                isIdentityPromotion(haveNft).
                currentIdentityImgUrl(IdentityImgUtil.getIdentityRankImaUrl(currentIdentity,haveNft)).
                currentIdentityImgUrlNo(IdentityImgUtil.getIdentityRankImaUrlNo(currentIdentity)).
                build();
    }

    @NotNull
    private String getRedisCacheKey() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long userId = loginUser.getUserId();
        String username = loginUser.getUsername();
        return CacheConstants.COOLDOWN_TIME_FOR_IDENTITY_PROMOTION+userId+":"+username;
    }


    /**
     * 该用户是否具有 身份卡或碎片 藏品
     *
     * @param userIdentityRank 用户身份段位信息
     * @param userId 用户id
     * @return IdentityPromotionVo （当前身份段位和是否可以晋升）
     */
    public Boolean isHaveNft(UserIdentityRank userIdentityRank,long userId) {
        //2.获取 身份 信息
        UserIdentity userIdentity = getUserIdentity(userIdentityRank);
        //3.查询用户有没有 身份卡 或 碎片 （满足两者其中之一都可以显示身份晋升按钮）
        return userIdentity==null?Boolean.FALSE:isHaveIdentityCardOrFragments(
                userIdentity.getIsIdentityCard()==1,
                userIdentity.getIsFragments()==1,
                userIdentity.getIdentityCardNftId(),
                userIdentity.getFragmentNftId(),
                userId
        );
    }


    /**
     * ***************************************TODO2: 晋升详情
     * ***************************************{@link #identityPromotionDetails}
     *
     *
     * 1.通过身份段位id获取对应的段位信息
     * 2.判断是否为最高段位
     * 2.1 若是最高段位，通过身份段位id获取下一级 身份信息
     * 2.2 若不是最高段位，则通过当前查询到的身份段位信息中的 身份id获取对应的 身份信息
     *
     * @param userId 用户id
     * @return map
     */
    public Map<String, PromotionVo> identityPromotionDetails(Long userId) {
        //1.获取 身份段位 信息
        UserIdentityRank userIdentityRank = getUserIdentityRank(userId);
        //2.获取 身份 信息
        UserIdentity userIdentity = getUserIdentity(userIdentityRank);
        if (userIdentity==null) {
            throw new ServiceException("当前用户身份等级已为最高身份等级！");
        }
        //3.判断 身份卡 和 碎片 晋升都支持
        //3.1 身份卡晋升
        IdentityCardPromotionVo identityCard =  identityCard(userIdentity,userIdentityRank,userId);
        //3.2 碎片晋升
        FragmentsPromotionVo fragments = fragments(userIdentity,userIdentityRank,userId);
        //3.1.判断冷却
        PromotionSuccessVo finalSuccessVo = getPromotionSuccessVo();
        return new HashMap<String,PromotionVo>(3){{
            if (identityCard!=null) {
                put(UserIdentityPromotionEnum.IDENTITY_CARD.promotion(),identityCard);
            }
            if (fragments!=null) {
                put(UserIdentityPromotionEnum.FRAGMENTS.promotion(),fragments);
            }
            if(finalSuccessVo !=null){
                put("promotionSuccessVo", finalSuccessVo);
            }
            this.forEach((key, value) -> log.info("identityPromotionDetails[身份晋升详情]:{}-{}", key, value));
        }};
    }

    /**
     *
       冷却信息（如果有冷却信息说明刚晋升过，前端用此条件判断）

     * @return 冷却信息
     */
    @Nullable
    private PromotionSuccessVo getPromotionSuccessVo() {
        PromotionSuccessVo successVo = null;
        String redisCacheKey = getRedisCacheKey();
        Object cacheObject = this.redisCache.getCacheObject(redisCacheKey);
        if (cacheObject!=null) {
            successVo = (PromotionSuccessVo)((HashMap<String,Object>)cacheObject).get("successVo");
            successVo.setExpire(this.redisCache.getExpire(redisCacheKey));
        }
        return successVo;
    }

    /**
     * 查询用户有没有 身份卡 或 碎片
     *
     * @param isIdentityCard 是否支持身份卡
     * @param isFragments 是否支持碎片
     * @param identityCardNftId 身份卡藏品ID
     * @param fragmentNftId 碎片藏品ID
     * @param userId 用户id
     * @return true-显示身份晋升按钮
     */
    private Boolean isHaveIdentityCardOrFragments(boolean isIdentityCard,boolean isFragments,Long identityCardNftId, Long fragmentNftId,long userId) {
        //1 是否有对应身份卡藏品
        Boolean isHaveIdentityCard = isIdentityCard && this.sysUserNftService.isHaveNft(identityCardNftId, userId);
        //2 是否有对应碎片藏品
        Boolean isHaveFragments = isFragments && this.sysUserNftService.isHaveNft(fragmentNftId, userId);
        //  满足两者其中之一
        return isHaveIdentityCard || isHaveFragments;
    }

    /**
     * 当前用户 通过 身份段位id 获取对应 身份段位信息
     *
     * @param userId 用户id
     * @return 身份段位信息
     */
    @NotNull
    public UserIdentityRank getUserIdentityRank(Long userId) {
        Long identityRankId = userService.selectUserById(userId).getIdentityRankId();
        Assert.notNull(identityRankId,"身份段位id不能为空！");
        UserIdentityRank userIdentityRank = this.getById(identityRankId);
        Assert.notNull(userIdentityRank,"该身份段位不存在！");
        return userIdentityRank;
    }

    /**
     * 通过 身份id 获取对应 身份信息
     * @param userIdentityRank 身份信息
     * @return 身份信息
     */
    private UserIdentity getUserIdentity(UserIdentityRank userIdentityRank) {
        //判断是否为最高段位,来获取对应的身份信息
        UserIdentity userIdentity;
        if (userIdentityRank.getIsHighest()==1) {
            //若是最高段位，通过身份段位id获取下一级身份
            userIdentity = this.userIdentityService.getNextIdentity(userIdentityRank.getId());
        }else{
            //若不是最高段位，则通过当前查询到的身份段位信息中的 身份id获取对应的 身份信息
            Assert.notNull(userIdentityRank.getIdentityId(),"身份id不能为空！");
            userIdentity = this.userIdentityService.getById(userIdentityRank.getIdentityId());
        }
        return userIdentity;
    }

    /**
     * 身份卡晋升
     *
     * @param userIdentity 身份
     * @param userIdentityRank 身份段位
     * @param userId 用户id
     * @return 身份卡晋升封装
     */
    private IdentityCardPromotionVo identityCard(UserIdentity userIdentity, UserIdentityRank userIdentityRank,Long userId) {
        //不支持身份卡晋升
        if (userIdentity.getIsIdentityCard()==0) {
            return null;
        }
        //身份卡晋升时，需要判断当前等级是否为对应身份的最大等级，否则不能通过身份卡去晋升
        if (userIdentityRank.getIsHighest()==0) {
            return null;
        }
        //如果用户有身份卡藏品，则返回对应的身份卡藏品藏品id；如果有多个返回最先拥有的身份卡藏品
        Long nftNumberId = this.sysUserNftService.getAnyNftNumber(userIdentity.getIdentityCardNftId(), userId);
        //藏品数量
        long nftNumberCounts = nftNumberId==null?0:this.sysUserNftService.getNftNumberCounts(userIdentity.getIdentityCardNftId(), userId);
        //根据 身份卡藏品id 获取 藏品主图地址
        String nftMainImg = this.nftService.getNftMainImg(userIdentity.getIdentityCardNftId());
        //根据 当前等级是否为最高等级来获取 晋升身份 和 最高装备升级等级 （否-获取当前身份段位的最高等级|是-获取下一个身份段位的最高等级）
        String promotionIdentityAndMaxEquipUpLevel = this.userIdentityRankMapper.identityCardPromotionIdentity(userIdentity.getId());
        String[] split = promotionIdentityAndMaxEquipUpLevel.split("&");
        //需要判断当前晋升的等级是否为对应身份的最大等级
        Boolean isMaxLevel = isMaxLevel(Long.parseLong(split[0]));
        return IdentityCardPromotionVo.builder()
                .isHaveIdentityCard(nftNumberCounts!=0)
                .spendNftType(UserIdentityPromotionEnum.IDENTITY_CARD.code())
                .nftNumberId(nftNumberId)
                .nftNumberCounts(nftNumberCounts)
                .currentIdentityId(userIdentityRank.getId())
                .promotionIdentityId(Long.parseLong(split[0]))
                .currentIdentity(userIdentityRank.getIdentityName()+(StringUtils.isBlank(userIdentityRank.getName())?"":userIdentityRank.getName()))
                .promotionIdentity(split[1])
                .minLevel(userIdentityRank.getMaxEquipUpLevel()+"级")
                .maxLevel(split[2])
                .isMaxLevel(isMaxLevel)
                .mainImg(nftMainImg)
                .spendHotBeans(new BigDecimal(userIdentity.getIdentityCardIntegralCost()))
                .coolingTime(userIdentity.getCooldownTime())
                .build();
    }


    /**
     * 碎片晋升
     *
     * @param userIdentity 身份
     * @param userIdentityRank 身份段位
     * @param userId 用户id
     * @return 碎片晋升封装
     */
    private FragmentsPromotionVo fragments(UserIdentity userIdentity, UserIdentityRank userIdentityRank,Long userId) {
        //不支持碎片晋升
        if (userIdentity.getIsFragments()==0) {
            return null;
        }
        //如果用户有碎片藏品，则返回对应的碎片藏品藏品id；如果有多个返回最先拥有的碎片藏品
        Long nftNumberId = this.sysUserNftService.getAnyNftNumber(userIdentity.getFragmentNftId(), userId);
        //藏品数量
        long nftNumberCounts = nftNumberId==null?0:this.sysUserNftService.getNftNumberCounts(userIdentity.getFragmentNftId(), userId);
        //根据 碎片藏品id 获取 藏品主图地址
        String nftMainImg = this.nftService.getNftMainImg(userIdentity.getFragmentNftId());
        //根据 当前等级是否为最高等级来获取 晋升身份 和 最高装备升级等级（否-获取当前身份段位的下一个等级|是-获取下一个身份段位的第一个等级）
        String promotionIdentityAndMaxEquipUpLevel = fragmentsPromotionIdentity(userIdentityRank,userIdentity.getId());
        String[] split = promotionIdentityAndMaxEquipUpLevel.split("&");
        //计算碎片晋升需要的热豆数量
        BigDecimal spendHotBeans = countSpendHotBeans(userIdentity.getFragmentIntegralCost(),userIdentity.getFragmentIntegralCostFactor(),userIdentityRank);
        //需要判断当前晋升的等级是否为对应身份的最大等级
        Boolean isMaxLevel = isMaxLevel(Long.parseLong(split[0]));
        return FragmentsPromotionVo.builder()
                .isHaveFragments(nftNumberCounts!=0)
                .spendNftType(UserIdentityPromotionEnum.FRAGMENTS.code())
                .nftNumberId(nftNumberId)
                .nftNumberCounts(nftNumberCounts)
                .currentIdentityId(userIdentityRank.getId())
                .promotionIdentityId(Long.parseLong(split[0]))
                .currentIdentity(userIdentityRank.getIdentityName()+ (StringUtils.isBlank(userIdentityRank.getName())?"":userIdentityRank.getName()))
                .promotionIdentity(split[1])
                .minLevel(userIdentityRank.getMaxEquipUpLevel()+"级")
                .maxLevel(split[2])
                .isMaxLevel(isMaxLevel)
                .mainImg(nftMainImg)
                .spendHotBeans(spendHotBeans)
                .coolingTime(userIdentity.getCooldownTime())
                .build();
    }

    /**
     * 计算碎片晋升 需要消耗的 热豆数量
     *
     * @param fragmentIntegralCost  一段热豆消耗：作用于升级到该身份的第一次消耗，例：【普通水友】升级到【竞技者lv.1】时需要消耗的热豆，正整数
     * @param fragmentIntegralCostFactor 热度消耗系数：作用于身份一段之后升级的热豆消耗计算，一段之后热豆消耗 ＝ 上一段热豆消耗 × 热豆消耗系数，
     *                                   例：生产者 → 竞技者lv.1（10热豆）→ 竞技者lv.2（10 * 1.5）→ 竞技者lv.3 {（10 * 1.5 ）* 1.5 }
     * @param userIdentityRank 身份段位信息
     *
     * @return BigDecimal
     */
    private BigDecimal countSpendHotBeans(Long fragmentIntegralCost, Float fragmentIntegralCostFactor,UserIdentityRank userIdentityRank) {
        DecimalFormat df = new DecimalFormat("#.00");//保留两位有效值
        if (userIdentityRank.getIsHighest()==1) {
            return new BigDecimal(df.format(fragmentIntegralCost));
        }
        BigDecimal bigDecimal = new BigDecimal(fragmentIntegralCost * Math.pow(fragmentIntegralCostFactor, userIdentityRank.getLevel()));
        return new BigDecimal(df.format(bigDecimal));
    }

    public static void main(String[] args) {
        System.out.println(Math.pow(1.5, 2));
        System.out.println(1.5*10);
        System.out.println(1.5*10*Math.pow(1.5, 2));
        System.out.println(new BigDecimal(1.5 * 10 * Math.pow(1.5, 2)));
        System.out.println(false && false);
        System.out.println(false && true);
        System.out.println(false || false);
        System.out.println(false || true);
    }


    /**
     * 获取 碎片 的晋升身份
     *
     * @param userIdentityRank 身份段位信息
     * @param identityId 身份id
     * @return 晋升身份
     */
    private String fragmentsPromotionIdentity(UserIdentityRank userIdentityRank, long identityId) {
        String promotionIdentity = null;
        if (userIdentityRank.getIsHighest()==1) {
            //为最高等级，获取下一个段位的 第一个等级 级别名称
            promotionIdentity = this.userIdentityRankMapper.getFirstPromotionIdentity(identityId);
        }else{
            //不为最高段位，获取当前段位等级的 下一个等级 级别名称
            promotionIdentity = this.userIdentityRankMapper.getNextPromotionIdentity(userIdentityRank.getIdentityId(),userIdentityRank.getLevel());
        }
        return promotionIdentity;
    }

    @Transactional(rollbackFor = Exception.class)
    public R<PromotionSuccessVo> identityPromotionConfirm(Integer spendNftType,long userId) {
        //1.获取 身份段位 信息
        UserIdentityRank userIdentityRank = getUserIdentityRank(userId);
        //2.获取 身份 信息
        UserIdentity userIdentity = getUserIdentity(userIdentityRank);
        //3.晋升操作
        //身份卡晋升
        if(spendNftType == UserIdentityPromotionEnum.IDENTITY_CARD.code()){
            //卡晋升信息
            IdentityCardPromotionVo identityCard =  identityCard(userIdentity,userIdentityRank,userId);
            //晋升
            return identityPromotionConfirm(BeanUtil.copyProperties(identityCard,IdentityRankUpgradeVo.class),userId);
        }
        //碎片晋升
        if(spendNftType == UserIdentityPromotionEnum.FRAGMENTS.code()){
            //获取碎片晋升信息
            FragmentsPromotionVo fragments = fragments(userIdentity,userIdentityRank,userId);
            //晋升
            return identityPromotionConfirm(BeanUtil.copyProperties(fragments,IdentityRankUpgradeVo.class),userId);
        }
        return R.fail("不支持该晋升方式！");
    }


    /**
     * ***************************************TODO3: 身份晋升确认
     * ***************************************{@link #identityPromotionConfirm}
     *
     * 1.判断冷却
     * 2.消耗身份卡 或 碎片
     * 3.消耗热豆
     * 4.修改用户段位
     * 5.新增用户段位升级记录
     * 6.设置冷却
     *
     * @param vo 请求对象
     * @param userId 用户id
     */
    @Transactional
    public R<PromotionSuccessVo> identityPromotionConfirm(IdentityRankUpgradeVo vo,long userId) {
        if(vo.getSpendNftType()!=UserIdentityPromotionEnum.IDENTITY_CARD.code() && vo.getSpendNftType()!=UserIdentityPromotionEnum.FRAGMENTS.code()){
           throw new ServiceException("藏品类型只能为（身份卡-0 碎片-1）");
        }
        //1.判断冷却
        String redisCacheKey = getRedisCacheKey();
        if (this.redisCache.getCacheObject(redisCacheKey)!=null) {
            throw new ServiceException("想要晋升身份？抱歉，冷却中！请耐心等待 "+vo.getCoolingTime()+" 分钟");
        }
        //2.消耗身份卡 或 碎片
        this.sysUserNftService.identityPromotionDestruction(userId,vo.getNftNumberId());
        //3.消耗热豆
        this.sysUserWalletService.reduce(userId, UserWalletEnum.INTEGRAL,vo.getSpendHotBeans(), WalletChangeTypeEnum.IDENTITY_PROMOTION,vo.getCurrentIdentityId(),"身份晋升");
        //4.修改用户段位
        this.sysUserMapper.updateUserIdentityRank(userId,vo.getPromotionIdentityId());
        //5.新增用户段位升级记录
        this.userRankUpgradeRecordService.insertUserRankUpgradeRecord(userId,vo);
        //6.设置冷却
        String redisCacheVal = userId+"-["+vo.getCurrentIdentityId()+"->"+vo.getPromotionIdentityId()+"]-["+vo.getCurrentIdentity()+"->"+vo.getPromotionIdentity()+"]";
        //7.身份晋升成功，返回对应信息。需要判断当前晋升的等级是否为对应身份的最大等级
        Boolean isMaxLevel = isMaxLevel(vo.getPromotionIdentityId());
        //8.晋升成功，返回晋升成功信息
        PromotionSuccessVo successVo = PromotionSuccessVo.builder()
                .promotionIdentity(vo.getPromotionIdentity())
                .promotionLevel(vo.getMaxLevel().replaceAll("级", ""))
                .isMaxLevel(isMaxLevel)
                .coolingTime(vo.getCoolingTime())
                .build();

        // 发送奖励扳手消息
        boolean send = mqSender.sendDelay(AppMqDelayEnum.NFT_USED, vo.getNftNumberId(), 10L);
        if (!send) {
            throw new ServiceException("发送奖励扳手消息失败！");
        }
        if (vo.getCoolingTime()>0) {
            this.redisCache.setCacheObject(redisCacheKey,new HashMap<String,Object>(2){{
                put("info",redisCacheVal);
                put("successVo",successVo);
            }},vo.getCoolingTime(), TimeUnit.MINUTES);
        }

        //升级成功，修改用户身份等级对应总打卡次数 设置下次打卡时间
        PunchUserConfig config = punchUserConfigService.getConfig(userId);
        PunchRule rule = punchRuleService.getById(config.getPunchRuleId());
        if (rule != null) {
            //设置升级后用户可打卡总次数
            rule.setPunchCount(this.getUserRankIdentityPunchCount(userId, rule.getPunchCount()));
            punchUserConfigService.upgradeEditPunchCount(userId, config, rule);
        }

        log.info("identityPromotionConfirm[晋升成功]：{}", (Object) this.redisCache.getCacheObject(redisCacheKey));
        return R.ok(successVo,"恭喜您，晋升成功啦！");
    }

    /**
     * 判断当前晋升的等级是否为最大等级
     *
     * @param promotionIdentityId  晋升的身份段位id
     * @return true - 是最大等级
     */
    @NotNull
    private Boolean isMaxLevel(Long promotionIdentityId) {
        return this.getOne(Wrappers.lambdaQuery(UserIdentityRank.class).select(UserIdentityRank::getIsHighest).eq(UserIdentityRank::getId, promotionIdentityId)).getIsHighest() == 1;
    }

    /**
     * ***************************************TODO4: 最高装备升级等级
     * ***************************************{@link #getMaxEquipUpLevelByUserId}
     *
     * @param userId 用户id
     * 获取最高装备升级等级
     */
    public int getMaxEquipUpLevelByUserId(long userId) {
        return getUserIdentityRank(userId).getMaxEquipUpLevel();
    }


    /**
     * 根据用户id检测当前用户身份是否满足特权升级
     */
    public boolean checkPrivilege(Long userId) {
        //1、获取用户的身份等级id
        Long identityRankId = userService.selectUserById(userId).getIdentityRankId();
        //2、判断用户身份等级是否大于等于系统配置的折扣升级等级
        return identityRankId >= sysConfigService.getValue(Config.Sys.Nft.融入折扣_身份等级);
    }

    /**
     * 根据用户id获取当前用户身份卡槽数量
     */
    public List<UserIdentityRankSlot> getSlotByUserId(Long userId) {
        //1、获取用户的身份等级id
        Long identityRankId = userService.selectUserById(userId).getIdentityRankId();
        // 根据身份等级id获取卡槽数量
        return userIdentityRankSlotService.list(Wrappers.lambdaQuery(UserIdentityRankSlot.class)
                .le(UserIdentityRankSlot::getIdentityRankId, identityRankId));
    }

    /**
     * ***************************************TODO5: 跟新最高装备升级等级
     * ***************************************{@link #updateCurrentIdentityRankMaxEquipUpLevel}
     *
     * 更新 当前身份 对应所有段位 的最高装备升级等级
     * 身份不同段位装备升级上限 ＝ （段位数值 － 1）×  每级跨度 ＋基础等级
     *
     * @param vo 请求对象
     */
    public void updateCurrentIdentityRankMaxEquipUpLevel(UserIdentityPermBasicVo vo) {
        //1 获取当前身份的所有等级（段位数值）
        LambdaQueryWrapper<UserIdentityRank> wrapper = Wrappers.lambdaQuery(UserIdentityRank.class)
                .select(UserIdentityRank::getId,UserIdentityRank::getLevel)
                .eq(UserIdentityRank::getIdentityId, vo.getIdentityId())
                .last("for update");
        List<UserIdentityRank> ranks = this.list(wrapper);
        if (ranks==null) {
            throw new ServiceException("当前身份还没有创建对应的段位！");
        }
        //2 更新 当前身份 对应所有段位 的最高装备升级等级
        for (UserIdentityRank rank : ranks) {
            int maxEquipUpLevel = (rank.getLevel()-1)*vo.getEquipUpMaxPerLevel()+vo.getEquipUpMaxBaseLevel();
            LambdaUpdateWrapper<UserIdentityRank> updateWrapper = Wrappers.lambdaUpdate(UserIdentityRank.class)
                    .setSql("max_equip_up_level = " + maxEquipUpLevel)
                    .eq(UserIdentityRank::getId, rank.getId());
            this.update(updateWrapper);
        }
    }

    /**
     * 异常回滚，清除清除redis缓存的晋升信息
     */
    public void clearRedisCacheIdentityRankInfo() {
        String redisCacheKey = getRedisCacheKey();
        Object cacheObject = this.redisCache.getCacheObject(redisCacheKey);
        if (cacheObject!=null) {
            this.redisCache.deleteObject(redisCacheKey);
            log.info("clearRedisCacheIdentityRankInfo：清除清除redis缓存的晋升信息成功！");
        }
    }


    /**
     * 检查用户等级是否大于等于目标等级
     * @param identityRankId
     * @return
     */
    public boolean checkUserRankGETargetRank(Long userId, Long identityRankId) {
        Long userRankId = userService.selectUserById(userId).getIdentityRankId();
        UserIdentityRank userRank = this.getById(userRankId);
        UserIdentityRank targetRank = this.getById(identityRankId);
        if (userRank.getIdentityId().equals(targetRank.getIdentityId())) {
            if (userRank.getLevel() >= targetRank.getLevel()) {
                return true;
            } else {
                return false;
            }
        } else {
            return userIdentityService.checkGE(userRank.getIdentityId(), targetRank.getIdentityId());
        }
    }

    /**
     * 获取用户等级对应打卡次数
     * (当前身份总打卡次数 ＝ 打卡时间段次数 × 装备打卡系数)
     */
    public Integer getUserRankIdentityPunchCount(Long userId, Integer punchCount) {
        SysUser sysUser = userService.selectUserById(userId);
        UserIdentityRank rank = this.getById(sysUser.getIdentityRankId());
        int count = punchCount * rank.getPunchRatio();
        return count == 0 ? punchCount : count;
    }
}

